import time
import cv2
import os
from fastapi.templating import Jinja2Templates
import paddleocr
from fastapi.responses import JSONResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles
from fastapi import FastAPI, File, Request, UploadFile, Form, Cookie, Depends, HTTPException, status

from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from fastapi.middleware.cors import CORSMiddleware
from typing import Optional, List
import jwt
from datetime import datetime, timedelta
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import Response
import sqlite3

from ImageProcess import ImageProcessor
import db  # 导入数据库模块


from fastapi import FastAPI, File, Request, UploadFile, Form, Cookie, Depends, HTTPException, status as http_status_codes # 明确导入并重命名
from fastapi.responses import RedirectResponse
from fastapi.templating import Jinja2Templates

import db
from fastapi import FastAPI, File, Request, UploadFile, Form, Cookie, Depends, HTTPException, status
from fastapi.responses import RedirectResponse, HTMLResponse # HTMLResponse 可能不需要，看情况
from fastapi.templating import Jinja2Templates


# JWT配置
SECRET_KEY = "water_meter_secret_key_for_jwt_token"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24  # 24小时过期

# 确保上传目录存在
os.makedirs('static/uploads', exist_ok=True)

# 初始化数据库
db.init_db()

ocr = paddleocr.PaddleOCR(use_gpu=False, lang='ch')
processor = ImageProcessor()

app = FastAPI()

# 添加CORS中间件
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 自定义异常处理中间件
class AuthExceptionMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        try:
            response = await call_next(request)
            return response
        except HTTPException as exc:
            if exc.status_code == status.HTTP_401_UNAUTHORIZED:
                # 认证失败，重定向到登录页面
                return RedirectResponse(url="/login", status_code=status.HTTP_302_FOUND)
            elif exc.status_code == status.HTTP_403_FORBIDDEN:
                # 权限不足，重定向到未授权页面
                return RedirectResponse(url="/unauthorized", status_code=status.HTTP_302_FOUND)
            else:
                # 其他异常，正常抛出
                raise exc

# 添加自定义异常处理中间件
app.add_middleware(AuthExceptionMiddleware)

app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")

# 创建OAuth2认证
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token", auto_error=False)

# 获取当前用户
async def get_current_user(request: Request, token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="无效的认证凭据",
        headers={"WWW-Authenticate": "Bearer"},
    )
    
    # 如果通过oauth2_scheme没有拿到token，尝试从cookie获取
    if not token:
        # 尝试从cookie中获取token
        auth_cookie = request.cookies.get("authorization")
        if not auth_cookie:
            raise credentials_exception
            
        try:
            scheme, token = auth_cookie.split()
            if scheme.lower() != "bearer":
                raise credentials_exception
        except:
            raise credentials_exception
        
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        user_id: int = payload.get("sub")
        if user_id is None:
            raise credentials_exception
    except Exception:
        raise credentials_exception
    
    user = db.get_user_by_id(user_id)
    if user is None:
        raise credentials_exception
    return user

# 获取当前用户（允许匿名）
async def get_optional_user(request: Request):
    auth_cookie = request.cookies.get("authorization")
    if not auth_cookie:
        return None
    
    try:
        scheme, token = auth_cookie.split()
        if scheme.lower() != "bearer":
            return None
        
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        user_id: int = payload.get("sub")
        if user_id is None:
            return None
        
        user = db.get_user_by_id(user_id)
        return user
    except:
        return None

# 验证管理员用户
async def get_admin_user(user = Depends(get_current_user)):
    if user["role"] != "admin":
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="需要管理员权限",
        )
    return user

# 创建访问令牌
def create_access_token(user_id: int):
    expires_delta = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    expire = datetime.utcnow() + expires_delta
    
    to_encode = {"sub": user_id, "exp": expire}
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

@app.get("/")
async def root(request: Request, user=Depends(get_optional_user)):
    # 如果用户未登录，重定向到登录页面
    if not user:
        return RedirectResponse(url="/login", status_code=status.HTTP_302_FOUND)
    
    # 用户已登录，显示正常首页
    readings = db.get_all_readings(user["id"] if user else None)
    return templates.TemplateResponse(
        request=request, name="index.html", context={
            "readings": readings,
            "user": user
        }
    )

@app.post("/upload_image")
async def upload_image(request: Request, image: UploadFile = File(...), user=Depends(get_current_user)):
    # Save the image to a file
    path = f"static/uploads/image_{time.time()}_{image.filename}"
    print("path:", path)
    
    try:
        with open(path, "wb") as f:
            f.write(image.file.read())
            number, code = parseImage(path)
            
        # 保存到数据库
        reading_id = db.add_meter_reading(code, number, path, user["id"])
        
        # 记录上传成功的审计日志
        db.add_audit_log(user["id"], user["username"], "上传水表图片", "成功", f"编码: {code}, 读数: {number}")
        
        return templates.TemplateResponse(
            request=request, name="index.html", context={
                "number": number,
                "code": code,
                "image": path,
                "readings": db.get_all_readings(user["id"]),
                "user": user,
                "success": "图片上传成功！已识别水表数据，账单将在管理员审核后生成",
            }
        )
    except Exception as e:
        # 记录上传失败的审计日志
        db.add_audit_log(user["id"], user["username"], "上传水表图片", "失败", str(e))
        
        return templates.TemplateResponse(
            request=request, name="index.html", context={
                "error": f"图像处理失败: {str(e)}",
                "readings": db.get_all_readings(user["id"]),
                "user": user
            }
        )

@app.get("/history")
async def history(request: Request, user=Depends(get_current_user)):
    # 根据用户角色决定显示哪些记录
    if user["role"] == "admin":
        readings = db.get_all_readings()  # 管理员可以看所有记录
    else:
        readings = db.get_all_readings(user["id"])  # 普通用户只能看自己的记录
        
    return templates.TemplateResponse(
        request=request, name="history.html", context={
            "readings": readings,
            "user": user
        }
    )

@app.get("/login")
async def login_page(request: Request, user=Depends(get_optional_user)):
    # 如果用户已登录，重定向到首页
    if user:
        return RedirectResponse(url="/", status_code=status.HTTP_302_FOUND)
        
    return templates.TemplateResponse(
        request=request, name="login.html", context={}
    )

@app.post("/login")
async def login(request: Request, username: str = Form(...), password: str = Form(...)):
    user, message = db.authenticate_user(username, password)
    if not user:
        return templates.TemplateResponse(
            request=request, name="login.html", context={
                "error": message
            }
        )
    
    # 创建访问令牌
    access_token = create_access_token(user["id"])
    
    # 创建重定向响应
    response = RedirectResponse(url="/", status_code=status.HTTP_303_SEE_OTHER)
    
    # 将令牌设置为cookie (修复cookie设置，确保cookie能被正确读取)
    response.set_cookie(
        key="authorization",
        value=f"Bearer {access_token}",
        httponly=True,
        max_age=60 * 60 * 24,  # 24小时
        expires=60 * 60 * 24,
        samesite="lax",  # 允许跨站点时携带Cookie
        secure=False     # 非HTTPS也可使用
    )
    
    return response

@app.get("/register")
async def register_page(request: Request, user=Depends(get_optional_user)):
    # 如果用户已登录，重定向到首页
    if user:
        return RedirectResponse(url="/", status_code=status.HTTP_302_FOUND)
        
    return templates.TemplateResponse(
        request=request, name="register.html", context={}
    )

@app.post("/register")
async def register(request: Request, username: str = Form(...), password: str = Form(...), confirm_password: str = Form(...)):
    # 检查密码是否匹配
    if password != confirm_password:
        return templates.TemplateResponse(
            request=request, name="register.html", context={
                "error": "两次输入的密码不匹配"
            }
        )
    
    # 注册用户
    success, message = db.register_user(username, password)
    if not success:
        return templates.TemplateResponse(
            request=request, name="register.html", context={
                "error": message
            }
        )
    
    # 注册成功，重定向到登录页面
    return templates.TemplateResponse(
        request=request, name="login.html", context={
            "success": "注册成功，请登录"
        }
    )

@app.get("/logout")
async def logout():
    response = RedirectResponse(url="/login")
    response.delete_cookie("authorization")
    return response

# 用户个人中心
@app.get("/profile")
async def profile_page(request: Request, user=Depends(get_current_user)):
    return templates.TemplateResponse(
        request=request, name="profile.html", context={
            "user": user
        }
    )

@app.post("/update_profile")
async def update_profile(
    request: Request, 
    username: str = Form(None), 
    old_password: str = Form(None), 
    new_password: str = Form(None),
    confirm_password: str = Form(None),
    user=Depends(get_current_user)
):
    # 校验表单
    if new_password and confirm_password and new_password != confirm_password:
        return templates.TemplateResponse(
            request=request, name="profile.html", context={
                "user": user,
                "error": "新密码两次输入不一致"
            }
        )
    
    # 至少一项有更新
    if not (username or (old_password and new_password)):
        return templates.TemplateResponse(
            request=request, name="profile.html", context={
                "user": user,
                "error": "未提供任何需要修改的信息"
            }
        )
    
    # 更新用户信息
    success, message = db.update_user_info(
        user["id"], 
        username if username and username != user["username"] else None,
        old_password, 
        new_password
    )
    
    if success:
        # 如果用户名更改，使用新信息获取用户
        updated_user = db.get_user_by_id(user["id"]) if username else user
        
        return templates.TemplateResponse(
            request=request, name="profile.html", context={
                "user": updated_user,
                "success": message
            }
        )
    else:
        return templates.TemplateResponse(
            request=request, name="profile.html", context={
                "user": user,
                "error": message
            }
        )

@app.get("/admin")
async def admin_panel(request: Request, user=Depends(get_admin_user)):
    # 获取所有用户
    users = db.get_all_users()
    readings = db.get_all_readings()
    
    return templates.TemplateResponse(
        request=request, name="admin.html", context={
            "users": users,
            "readings": readings,
            "user": user
        }
    )

@app.get("/admin/edit_user/{user_id}")
async def edit_user_page(request: Request, user_id: int, user=Depends(get_admin_user)):
    # 获取用户信息
    target_user = db.get_user_by_id(user_id)
    
    if not target_user:
        return RedirectResponse(url="/admin", status_code=status.HTTP_302_FOUND)
    
    return templates.TemplateResponse(
        request=request, name="edit_user.html", context={
            "target_user": target_user,
            "user": user
        }
    )

@app.post("/admin/update_user/{user_id}")
async def update_user(
    request: Request, 
    user_id: int, 
    username: str = Form(None), 
    role: str = Form(None),
    reset_password: bool = Form(False),
    user=Depends(get_admin_user)
):
    # 更新用户信息
    success, message = db.admin_update_user(user_id, username, role, reset_password)
    
    if success:
        if "新密码" in message:
            # 显示新密码，不立即重定向
            target_user = db.get_user_by_id(user_id)
            return templates.TemplateResponse(
                request=request, name="edit_user.html", context={
                    "target_user": target_user,
                    "user": user,
                    "success": message
                }
            )
        else:
            return RedirectResponse(url="/admin", status_code=status.HTTP_303_SEE_OTHER)
    else:
        target_user = db.get_user_by_id(user_id)
        return templates.TemplateResponse(
            request=request, name="edit_user.html", context={
                "target_user": target_user,
                "user": user,
                "error": message
            }
        )

@app.post("/admin/delete_user/{user_id}")
async def delete_user(request: Request, user_id: int, user=Depends(get_admin_user)):
    # 不允许删除自己
    if int(user_id) == user["id"]:
        return templates.TemplateResponse(
            request=request, name="admin.html", context={
                "users": db.get_all_users(),
                "readings": db.get_all_readings(),
                "user": user,
                "error": "无法删除当前登录的账户"
            }
        )
    
    # 删除用户
    success, message = db.delete_user(user_id)
    
    if success:
        return RedirectResponse(url="/admin", status_code=status.HTTP_303_SEE_OTHER)
    else:
        return templates.TemplateResponse(
            request=request, name="admin.html", context={
                "users": db.get_all_users(),
                "readings": db.get_all_readings(),
                "user": user,
                "error": message
            }
        )

@app.get("/unauthorized")
async def unauthorized(request: Request):
    return templates.TemplateResponse(
        request=request, name="unauthorized.html", context={
            "message": "您没有权限访问此页面"
        }
    )

# 账单管理相关路由
@app.get("/bills")
async def bills_page(request: Request, user=Depends(get_current_user)):
    # 根据用户角色获取账单
    if user["role"] == "admin":
        bills = db.get_user_bills(include_pending=True)  # 管理员可以看所有账单
    else:
        bills = db.get_user_bills(user["id"])  # 普通用户只能看已审核的账单
        
    return templates.TemplateResponse(
        request=request, name="bills.html", context={
            "bills": bills,
            "user": user
        }
    )

# 修改 GET /bill/{bill_id} 以处理消息参数
@app.get("/bill/{bill_id}")
async def bill_detail(request: Request, bill_id: int, user=Depends(get_current_user)):
    print(f"Fetching bill with ID: {bill_id} for user: {user['id']}")

    # 从查询参数中获取成功或错误消息
    success_message = request.query_params.get("success")
    error_message = request.query_params.get("error")

    target_bill = None
    # 管理员可以查看任何账单，普通用户只能查看自己的账单
    # 并且 db.get_user_bills 内部已经处理了权限，这里主要是为了找到特定的bill
    # 更优化的做法是直接从数据库按bill_id查询，并校验用户权限
    if user["role"] == "admin":
        all_bills_for_admin = db.get_user_bills(user_id=None, include_pending=True) # 获取所有，包括待审核
        target_bill = next((b for b in all_bills_for_admin if b["id"] == bill_id), None)
    else:
        # 普通用户也应该能看到自己的pending_review账单，以便了解状态
        user_specific_bills = db.get_user_bills(user_id=user["id"], include_pending=True)
        target_bill = next((b for b in user_specific_bills if b["id"] == bill_id and b["user_id"] == user["id"]), None)


    if not target_bill:
        print("Bill not found or user not authorized to view this bill.")
        # 可以重定向到账单列表并带上错误信息
        return RedirectResponse(url=request.url_for('bills_page').include_query_params(error="账单未找到或无权查看"), status_code=status.HTTP_302_FOUND)

    context = {
        "request": request,
        "bill": target_bill,
        "user": user
    }
    if success_message:
        context["success"] = success_message
    if error_message:
        context["error"] = error_message

    return templates.TemplateResponse(
        "bill_detail.html", context
    )



@app.get("/pay/{bill_id}")
async def pay_bill_page(request: Request, bill_id: int, user=Depends(get_current_user)):
    # 获取指定账单
    bills = db.get_user_bills(user["id"] if user["role"] != "admin" else None)
    bill = next((b for b in bills if b["id"] == bill_id), None)
    
    if not bill or bill["status"] != "unpaid":
        return RedirectResponse(url="/bills", status_code=status.HTTP_302_FOUND)
        
    return templates.TemplateResponse(
        request=request, name="payment.html", context={
            "bill": bill,
            "user": user
        }
    )

@app.post("/pay/{bill_id}")
async def process_payment(request: Request, bill_id: int, payment_method: str = Form(...), user=Depends(get_current_user)):
    # 处理支付
    success, message = db.pay_bill(bill_id, payment_method)
    
    # 记录支付操作审计日志
    db.add_audit_log(
        user["id"], 
        user["username"], 
        "支付账单", 
        "成功" if success else "失败", 
        f"账单ID: {bill_id}, 支付方式: {payment_method}, 结果: {message}"
    )
    
    if success:
        return templates.TemplateResponse(
            request=request, name="payment_success.html", context={
                "message": message,
                "user": user
            }
        )
    else:
        return templates.TemplateResponse(
            request=request, name="payment.html", context={
                "error": message,
                "user": user,
                "bill_id": bill_id
            }
        )

# 异常记录相关路由
@app.get("/anomalies")
async def anomalies_page(request: Request, user=Depends(get_current_user)):
    # 根据用户角色获取异常记录
    if user["role"] == "admin":
        anomalies = db.get_anomalies()  # 管理员可以看所有异常记录
    else:
        anomalies = db.get_anomalies(user["id"])  # 普通用户只能看自己的异常记录
        
    return templates.TemplateResponse(
        request=request, name="anomalies.html", context={
            "anomalies": anomalies,
            "user": user
        }
    )

@app.get("/anomaly/{anomaly_id}")
async def anomaly_detail(request: Request, anomaly_id: int, user=Depends(get_current_user)):
    # 获取指定异常记录
    anomalies = db.get_anomalies(user["id"] if user["role"] != "admin" else None)
    anomaly = next((a for a in anomalies if a["id"] == anomaly_id), None)
    
    if not anomaly:
        return RedirectResponse(url="/anomalies", status_code=status.HTTP_302_FOUND)
        
    return templates.TemplateResponse(
        request=request, name="anomaly_detail.html", context={
            "anomaly": anomaly,
            "user": user
        }
    )

@app.post("/resolve_anomaly/{anomaly_id}")
async def resolve_anomaly(request: Request, anomaly_id: int, resolution: str = Form(...), user=Depends(get_admin_user)):
    # 处理异常解决（仅管理员可用）
    success, message = db.resolve_anomaly(anomaly_id, resolution)
    
    if success:
        return RedirectResponse(url="/anomalies", status_code=status.HTTP_303_SEE_OTHER)
    else:
        return templates.TemplateResponse(
            request=request, name="anomaly_detail.html", context={
                "error": message,
                "user": user,
                "anomaly_id": anomaly_id
            }
        )

# 添加用户上报异常功能
@app.get("/report_anomaly")
async def report_anomaly_page(request: Request, user=Depends(get_current_user)):
    # 获取用户的水表
    readings = db.get_all_readings(user["id"])
    meter_codes = list(set([r["meter_code"] for r in readings if r["meter_code"]]))
    
    return templates.TemplateResponse(
        request=request, name="report_anomaly.html", context={
            "user": user,
            "meter_codes": meter_codes
        }
    )

@app.post("/report_anomaly")
async def process_report_anomaly(
    request: Request, 
    meter_code: str = Form(...), 
    anomaly_type: str = Form(...), 
    description: str = Form(...),
    user=Depends(get_current_user)
):
    # 手动添加异常记录
    conn = sqlite3.connect(db.DB_PATH)
    cursor = conn.cursor()
    
    try:
        cursor.execute("""
            INSERT INTO anomalies (user_id, meter_code, anomaly_type, description, report_date, status)
            VALUES (?, ?, ?, ?, ?, ?)
        """, (user["id"], meter_code, anomaly_type, description, 
              datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'unresolved'))
        
        conn.commit()
        conn.close()
        
        # 记录上报异常的审计日志
        db.add_audit_log(user["id"], user["username"], "上报异常", "成功", 
                        f"水表编码: {meter_code}, 异常类型: {anomaly_type}")
        
        return RedirectResponse(url="/anomalies", status_code=status.HTTP_303_SEE_OTHER)
    except Exception as e:
        conn.close()
        
        # 记录上报失败的审计日志
        db.add_audit_log(user["id"], user["username"], "上报异常", "失败", str(e))
        
        return templates.TemplateResponse(
            request=request, name="report_anomaly.html", context={
                "error": f"上报异常失败: {str(e)}",
                "user": user,
                "meter_codes": [meter_code]
            }
        )

# 水务规划相关路由
@app.get("/water_plans")
async def water_plans_page(request: Request, user=Depends(get_admin_user)):
    # 获取水务规划（仅管理员可见）
    plans = db.get_water_plans()
    
    return templates.TemplateResponse(
        request=request, name="water_plans.html", context={
            "plans": plans,
            "user": user
        }
    )

@app.get("/add_water_plan")
async def add_water_plan_page(request: Request, user=Depends(get_admin_user)):
    # 添加水务规划页面（仅管理员可用）
    return templates.TemplateResponse(
        request=request, name="add_water_plan.html", context={
            "user": user
        }
    )

@app.post("/add_water_plan")
async def process_add_water_plan(
    request: Request,
    plan_title: str = Form(...),
    description: str = Form(...),
    area: str = Form(...),
    population: int = Form(...),
    estimated_usage: float = Form(...),
    implementation_date: str = Form(...),
    plan_status: str = Form(..., alias="status"), # 使用 alias 来保持表单字段名为 'status'
    user=Depends(get_admin_user)
):
    # 处理添加水务规划
    try:
        # 打印输入参数
        print(f"Received parameters - plan_title: {plan_title}, description: {description}, area: {area}, population: {population}, estimated_usage: {estimated_usage}, implementation_date: {implementation_date}, plan_status: {plan_status}")

        # 验证输入数据
        if population <= 0:
            error_message = "人口数量必须大于0"
            print(error_message)
            return templates.TemplateResponse(
                request=request, name="add_water_plan.html", context={
                    "error": error_message,
                    "user": user,
                    "plan_title": plan_title, # 将已填数据传回，改善用户体验
                    "description": description,
                    "area": area,
                    "population": population,
                    "estimated_usage": estimated_usage,
                    "implementation_date": implementation_date,
                    "current_status": plan_status # 注意这里用的是 plan_status
                }
            )

        if estimated_usage <= 0:
            error_message = "预计用水量必须大于0"
            print(error_message)
            return templates.TemplateResponse(
                request=request, name="add_water_plan.html", context={
                    "error": error_message,
                    "user": user,
                    "plan_title": plan_title,
                    "description": description,
                    "area": area,
                    "population": population,
                    "estimated_usage": estimated_usage,
                    "implementation_date": implementation_date,
                    "current_status": plan_status
                }
            )

        # 添加水务规划，注意这里传递的是 plan_status
        success, message = db.add_water_plan(
            plan_title, description, area, population,
            estimated_usage, implementation_date, plan_status # 使用 plan_status
        )

        print(f"Database operation result - success: {success}, message: {message}")

        if success:
            # 记录成功的审计日志
            db.add_audit_log(
                user["id"],
                user["username"],
                "添加水务规划",
                "成功",
                f"规划名称: {plan_title}, 区域: {area}, 人口: {population}"
            )
            print("Redirecting to /water_plans")
            # 现在这里的 status 指的是 fastapi.status 或 starlette.status
            return RedirectResponse(url="/water_plans", status_code=status.HTTP_303_SEE_OTHER)
        else:
            # 记录失败的审计日志
            db.add_audit_log(
                user["id"],
                user["username"],
                "添加水务规划",
                "失败",
                message
            )
            return templates.TemplateResponse(
                request=request, name="add_water_plan.html", context={
                    "error": message,
                    "user": user,
                    "plan_title": plan_title,
                    "description": description,
                    "area": area,
                    "population": population,
                    "estimated_usage": estimated_usage,
                    "implementation_date": implementation_date,
                    "current_status": plan_status
                }
            )
    except ValueError as e:
        # ... (保持不变)
        error_message = f"输入数据格式错误: {str(e)}"
        print(error_message)
        db.add_audit_log(user["id"], user["username"], "添加水务规划", "失败", error_message)

        return templates.TemplateResponse(
            request=request, name="add_water_plan.html", context={
                "error": error_message,
                "user": user,
                "plan_title": plan_title,
                "description": description,
                "area": area,
                "population": population,
                "estimated_usage": estimated_usage,
                "implementation_date": implementation_date,
                "current_status": plan_status if 'plan_status' in locals() else None # 确保 plan_status 已定义
            }
        )
    except Exception as e:
        # ... (保持不变)
        error_message = f"系统错误: {str(e)}"
        print(f"添加水务规划错误: {str(e)}")
        print(f"Exception type: {type(e)}")
        # print(f"Exception dir: {dir(e)}") # 通常不需要打印 dir

        db.add_audit_log(user["id"], user["username"], "添加水务规划", "失败", error_message)

        return templates.TemplateResponse(
            request=request, name="add_water_plan.html", context={
                "error": error_message,
                "user": user,
                "plan_title": plan_title,
                "description": description,
                "area": area,
                "population": population,
                "estimated_usage": estimated_usage,
                "implementation_date": implementation_date,
                "current_status": plan_status if 'plan_status' in locals() else None # 确保 plan_status 已定义
            }
        )
@app.get("/edit_water_plan/{plan_id}")
async def edit_water_plan_page(request: Request, plan_id: int, user=Depends(get_admin_user)):
    # 获取指定规划
    plans = db.get_water_plans()
    plan = next((p for p in plans if p["id"] == plan_id), None)
    
    if not plan:
        return RedirectResponse(url="/water_plans", status_code=status.HTTP_302_FOUND)
        
    return templates.TemplateResponse(
        request=request, name="edit_water_plan.html", context={
            "plan": plan,
            "user": user
        }
    )

@app.post("/edit_water_plan/{plan_id}")
async def process_edit_water_plan(
    request: Request,
    plan_id: int,
    plan_title: str = Form(...),
    description: str = Form(...),
    area: str = Form(...),
    population: int = Form(...),
    estimated_usage: float = Form(...),
    implementation_date: str = Form(...),
    plan_status: str = Form(..., alias="status"), # <--- 修改这里，使用 alias
    user=Depends(get_admin_user)
):
    # 用于在出错时回填表单的数据字典
    form_data_for_template = {
        "id": plan_id,
        "plan_title": plan_title,
        "description": description,
        "area": area,
        "population": population,
        "estimated_usage": estimated_usage,
        "implementation_date": implementation_date,
        "status": plan_status # 使用 plan_status 填充 'status' 键，因为模板可能期望 'status'
    }

    try:
        # 验证输入数据
        if population <= 0:
            return templates.TemplateResponse(
                request=request, name="edit_water_plan.html", context={
                    "error": "人口数量必须大于0",
                    "plan": form_data_for_template,
                    "user": user,
                    "request": request # 确保传递 request 给模板
                }
            )

        if estimated_usage <= 0:
            return templates.TemplateResponse(
                request=request, name="edit_water_plan.html", context={
                    "error": "预计用水量必须大于0",
                    "plan": form_data_for_template,
                    "user": user,
                    "request": request
                }
            )

        # 编辑水务规划，注意这里传递的是 plan_status
        success, message = db.update_water_plan(
            plan_id, plan_title, description, area, population,
            estimated_usage, implementation_date, plan_status # <--- 使用 plan_status
        )

        if success:
            # 记录成功的审计日志
            db.add_audit_log(
                user["id"],
                user["username"],
                "编辑水务规划",
                "成功",
                f"规划ID: {plan_id}, 规划名称: {plan_title}, 区域: {area}"
            )
            # 使用明确导入的 http_status_codes
            return RedirectResponse(url=request.url_for('water_plans_page'), status_code=http_status_codes.HTTP_303_SEE_OTHER)
        else:
            # 记录失败的审计日志
            db.add_audit_log(
                user["id"],
                user["username"],
                "编辑水务规划",
                "失败",
                message
            )
            return templates.TemplateResponse(
                request=request, name="edit_water_plan.html", context={
                    "error": message,
                    "plan": form_data_for_template,
                    "user": user,
                    "request": request
                }
            )
    except ValueError as e:
        # 处理数值转换错误
        error_message = f"输入数据格式错误: {str(e)}"
        db.add_audit_log(user["id"], user["username"], "编辑水务规划", "失败", error_message)

        return templates.TemplateResponse(
            request=request, name="edit_water_plan.html", context={
                "error": error_message,
                "plan": form_data_for_template, # 回填数据
                "user": user,
                "request": request
            }
        )
    except Exception as e:
        # 添加异常捕获，记录详细错误信息
        error_message = f"系统错误: {str(e)}"
        print(f"编辑水务规划错误: {str(e)}")

        db.add_audit_log(user["id"], user["username"], "编辑水务规划", "失败", error_message)

        return templates.TemplateResponse(
            request=request, name="edit_water_plan.html", context={
                "error": error_message,
                "plan": form_data_for_template, # 回填数据
                "user": user,
                "request": request
            }
        )

def parseImage(image):
    processor.process(image)

    result = ocr.ocr(processor.number_image, cls=True)
    result1 = ocr.ocr(processor.code_image, cls=True)

    code = ""
    number = ""
    if result is not None and len(result) > 0:
        if result[0] is not None and len(result[0]) > 0:
            code = result[0][0][-1][0]
    
    if result1 is not None and len(result1) > 0:
        if result1[0] is not None and len(result1[0]) > 0:
            number = result1[0][0][-1][0]

    return number, code

# 添加系统安全审计路由
@app.get("/admin/audit")
async def audit_logs(request: Request, user=Depends(get_admin_user)):
    logs = db.get_audit_logs()
    
    return templates.TemplateResponse(
        request=request, name="audit_logs.html", context={
            "logs": logs,
            "user": user
        }
    )

@app.get("/create_bill")
async def create_bill_page(request: Request, user=Depends(get_current_user)):
    """显示创建账单页面"""
    return templates.TemplateResponse(
        request=request, name="create_bill.html", context={
            "user": user
        }
    )

@app.post("/create_bill")
async def process_create_bill(
    request: Request, 
    meter_code: str = Form(...), 
    start_reading: float = Form(...), 
    end_reading: float = Form(...),
    user=Depends(get_current_user)
):
    """处理创建账单请求"""
    # 验证结束读数大于起始读数
    if end_reading <= start_reading:
        return templates.TemplateResponse(
            request=request, name="create_bill.html", context={
                "user": user,
                "error": "结束读数必须大于起始读数"
            }
        )
    
    try:
        # 计算水量
        water_usage = end_reading - start_reading
        
        # 连接数据库
        conn = sqlite3.connect(db.DB_PATH)
        cursor = conn.cursor()
        
        # 计算水费 - 直接使用返回值，不尝试解包
        amount = db.calculate_water_bill(cursor, water_usage)
        
        # 创建账单（状态为待审核）
        cursor.execute("""
            INSERT INTO bills (user_id, meter_code, start_reading, end_reading, water_usage, 
                             amount, status, bill_date)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?)
        """, (user["id"], meter_code, start_reading, end_reading, water_usage, 
             amount, "pending_review", datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')))
        
        conn.commit()
        conn.close()
        
        # 记录审计日志
        db.add_audit_log(user["id"], user["username"], "创建账单", "成功", 
                       f"水表: {meter_code}, 用水量: {water_usage}, 金额: {amount}")
        
        # 重定向到账单列表页面
        return templates.TemplateResponse(
            request=request, name="create_bill.html", context={
                "user": user,
                "success": "账单已创建，请等待管理员审核"
            }
        )
    except Exception as e:
        # 记录失败日志
        db.add_audit_log(user["id"], user["username"], "创建账单", "失败", str(e))
        
        return templates.TemplateResponse(
            request=request, name="create_bill.html", context={
                "user": user,
                "error": f"创建账单失败: {str(e)}"
            }
        )

@app.get("/admin/pending_bills")
async def pending_bills_page(request: Request, user=Depends(get_admin_user)):
    """显示待审核的账单列表"""
    # 获取所有待审核的账单
    bills = db.get_user_bills(status="pending_review")
    
    return templates.TemplateResponse(
        request=request, name="pending_bills.html", context={
            "bills": bills,
            "user": user
        }
    )

@app.get("/admin/review_bill/{bill_id}")
async def review_bill_page(request: Request, bill_id: int, user=Depends(get_admin_user)):
    """显示审核账单页面"""
    # 获取待审核的账单
    bills = db.get_user_bills(status="pending_review")
    bill = next((b for b in bills if b["id"] == bill_id), None)
    
    if not bill:
        return RedirectResponse(url="/admin/pending_bills", status_code=status.HTTP_302_FOUND)
        
    return templates.TemplateResponse(
        request=request, name="review_bill.html", context={
            "bill": bill,
            "user": user
        }
    )

@app.post("/admin/review_bill/{bill_id}")
async def process_review_bill(
    request: Request, 
    bill_id: int, 
    action: str = Form(...),
    user=Depends(get_admin_user)
):
    """处理账单审核"""
    approve = action == "approve"
    
    # 审核账单
    success, message = db.review_bill(bill_id, user["id"], approve)
    
    # 记录审计日志
    db.add_audit_log(
        user["id"], 
        user["username"], 
        "审核账单", 
        "成功" if success else "失败", 
        f"账单ID: {bill_id}, 操作: {'批准' if approve else '拒绝'}, 结果: {message}"
    )
    
    if success:
        return RedirectResponse(url="/admin/pending_bills?success=" + message, status_code=status.HTTP_303_SEE_OTHER)
    else:
        return templates.TemplateResponse(
            request=request, name="review_bill.html", context={
                "error": message,
                "user": user,
                "bill_id": bill_id
            }
        )
#D:\02order_info\0522\200rweb\py312200rwebocr_with_fastapi\water_meter.py
@app.get("/admin/pending_bills_count")
async def get_pending_bills_count(user=Depends(get_admin_user)):
    """获取待审核账单数量"""
    bills = db.get_user_bills(status="pending_review")
    return {"count": len(bills)}




# 新增接口：处理管理员在账单详情页的审核操作
@app.post("/bill/{bill_id}/review_action")
async def process_bill_review_from_detail(
    request: Request,
    bill_id: int,
    action: str = Form(...),  # 'approve' or 'reject'
    user=Depends(get_admin_user) # 确保只有管理员可以操作
):
    approve = (action == "approve")
    success, message = db.review_bill(bill_id, user["id"], approve)

    # 记录审计日志
    db.add_audit_log(
        user["id"],
        user["username"],
        "账单详情页审核",
        "成功" if success else "失败",
        f"账单ID: {bill_id}, 操作: {'批准' if approve else '拒绝'}, 结果: {message}"
    )

    # 重定向回账单详情页，并附带成功或失败消息
    redirect_url = request.url_for('bill_detail', bill_id=bill_id)
    if success:
        return RedirectResponse(redirect_url.include_query_params(success=message), status_code=status.HTTP_303_SEE_OTHER)
    else:
        return RedirectResponse(redirect_url.include_query_params(error=message), status_code=status.HTTP_303_SEE_OTHER)

    # 例如，您现有的 process_review_bill 可能如下：
    @app.post("/admin/review_bill/{bill_id}")
    async def process_review_bill(  # 这个是处理来自 review_bill.html 页面的
            request: Request,
            bill_id: int,
            action: str = Form(...),
            user=Depends(get_admin_user)
    ):
        """处理账单审核（来自专门的审核页面）"""
        approve = action == "approve"
        success, message = db.review_bill(bill_id, user["id"], approve)

        db.add_audit_log(
            user["id"],
            user["username"],
            "账单审核（列表页）",  # 区分来源
            "成功" if success else "失败",
            f"账单ID: {bill_id}, 操作: {'批准' if approve else '拒绝'}, 结果: {message}"
        )

        if success:
            # 来自审核列表页的操作，成功后返回审核列表页
            return RedirectResponse(url=request.url_for('pending_bills_page').include_query_params(success=message),
                                    status_code=status.HTTP_303_SEE_OTHER)
        else:
            # 失败了，可能返回到具体的审核页面并带上错误
            # 或者也返回到待审核列表，取决于您的设计
            return templates.TemplateResponse(
                "review_bill.html",  # 假设失败了还停留在 review_bill.html
                context={
                    "request": request,
                    "error": message,
                    "user": user,
                    "bill_id": bill_id  # 需要重新获取 bill 数据传给模板
                }
            )
